--
-- Author: zhouzhanglin
-- Date: 2014-10-09 14:05:50
--
----@module ext.UIScrollView
local UIScrollView = class("UIScrollView",ext.Component)

UIScrollView.DIRECTION_BOTH         = 0
UIScrollView.DIRECTION_VERTICAL     = 1
UIScrollView.DIRECTION_HORIZONTAL   = 2

function UIScrollView:ctor(size,direction,count)
    UIScrollView.super.ctor(self)

    count = count or 1
    self:setAnchorPoint(cc.p(0.5,0.5))
    self:setContentSize(size.width,size.height)
    self:setTouchEnabled(true)
    self:setTouchCaptureEnabled(true)

    self.direction = direction or UIScrollView.DIRECTION_HORIZONTAL
    self.lockDrag = false 
    self.maxSpeed = 60 
    self.speed=0.4

    self._renderSize = cc.size(50,50) --render size
    self._row = 5
    self._col=5 
    if self.direction==UIScrollView.DIRECTION_HORIZONTAL then
        self._row = count
    elseif self.direction==UIScrollView.DIRECTION_VERTICAL then
        self._col = count
    end
    self._beganPos=cc.p(0,0)
    self._containerPos=cc.p(0,0)
    self._delta=cc.p(0,0)
    self._offsetX = 0
    self._offsetY = 0 
    self._touchIsDown = false 


    self._container = display.newNode()
    if self.direction==UIScrollView.DIRECTION_HORIZONTAL then
        self._clipNode = display.newClippingRegionNode(cc.rect(0,-size.height/2,size.width,size.height))
    elseif self.direction==UIScrollView.DIRECTION_VERTICAL then
        self._clipNode = display.newClippingRegionNode(cc.rect(-size.width/2,-size.height,size.width,size.height))
    end
    self._clipNode:addChild(self._container)
    --设置到最左边和最上边
    if self.direction==UIScrollView.DIRECTION_HORIZONTAL then
        self._clipNode:setPosition( 0,size.height/2)
    elseif self.direction==UIScrollView.DIRECTION_VERTICAL then
        self._clipNode:setPosition(size.width/2,size.height)
    end
    self:addChild(self._clipNode)

    self:addNodeEventListener(cc.NODE_ENTER_FRAME_EVENT, handler(self, self._onEnterFrame))
    self:scheduleUpdate()
    self:addNodeEventListener(cc.NODE_TOUCH_EVENT, handler(self, self._onTouchHandler))
end

function UIScrollView:setClippingEnabled(value)
    self._clipNode:setClippingEnabled(value)
end

function UIScrollView:setRenders(renders,renderSize,rowGap,colGap)
    if renders==nil or #renders==0 then
        error("renders不能为空",1)
        return
    end

    if renderSize == nil then
        local size = renders[1]:getCascadeBoundingBox().size
        renderSize = cc.size(size.width,size.height)
    end

    if renderSize.width==0 or renderSize.height==0 then
        local box = renders[1]:getBoundingBox()
        renderSize.width = box.width
        renderSize.height = box.height
    end
    rowGap = rowGap or 15
    colGap = colGap or 5

    self._renderSize = renderSize
    local nn = display.newNode()
    self._container:removeAllChildren()
    self._container:setPosition(0,0)
    self._endX = 0
    self._endY = 0

    if self.direction==UIScrollView.DIRECTION_HORIZONTAL then
        self._col = math.ceil(#renders/self._row)
        local wid = self._col*(renderSize.width+colGap)-colGap+renderSize.width
        self._container:setContentSize( wid , renderSize.height*self._row)
        self:_showRenderByH(renders,rowGap,colGap)
    elseif self.direction==UIScrollView.DIRECTION_VERTICAL then
        self._row = math.ceil(#renders/self._col)
        local het =  self._row*(renderSize.height+rowGap)-rowGap+renderSize.height
        self._container:setContentSize(renderSize.width*self._col , het )
        self:_showRenderByV(renders,rowGap,colGap)
    end
end


function UIScrollView:_showRenderByH(renders,rowGap,colGap)
    local tempRow = 0
    local tempCol = 0
    for i, render in ipairs(renders) do
        render:setTouchSwallowEnabled(false)
        render:setPositionX( tempCol*(self._renderSize.width+colGap) + self._renderSize.width/2 )
        render:setPositionY( -tempRow*(self._renderSize.height+rowGap) + (self._row-1)*self._renderSize.height/2 )
        self._container:addChild(render)
        tempRow = tempRow+1
        if tempRow==self._row then
            tempRow = 0;
            tempCol = tempCol+1
        end
    end
end

function UIScrollView:_showRenderByV(renders,rowGap,colGap)
    local tempRow = 0
    local tempCol = 0
    for i, render in ipairs(renders) do
        render:setTouchSwallowEnabled(false)
        render:setPositionX( tempCol*(self._renderSize.width+colGap) - (self._col-1)*self._renderSize.width/2 )
        render:setPositionY( -tempRow*(self._renderSize.height+rowGap) - self._renderSize.height/2 )
        self._container:addChild(render)
        tempCol = tempCol+1
        if tempCol==self._col then
            tempCol = 0
            tempRow = tempRow+1
        end
    end
end


function UIScrollView:_onEnterFrame(dt)
    local spd = 0
    if self.direction==UIScrollView.DIRECTION_VERTICAL then

        local speedY = (self._endY-self._container:getPositionY())*self.speed 
        if not self._touchIsDown and self._endY-self._container:getContentSize().height>-self:getContentSize().height then 
            speedY = speedY * 0.2 
        elseif not self._touchIsDown and self._endY<0 then
            speedY = speedY * 0.2 
        end
        if speedY>self.maxSpeed then 
            speedY=self.maxSpeed
        elseif speedY <-self.maxSpeed then 
            speedY = -self.maxSpeed  
        end
        if math.abs(speedY)<0.1 then 
            speedY = 0 
            self._container:setPositionY( self._endY )
        else
            self._container:setPositionY( self._container:getPositionY()+speedY )
        end
        spd = speedY

    elseif self.direction==UIScrollView.DIRECTION_HORIZONTAL then

        local speedX = (self._endX-self._container:getPositionX())*self.speed 

        if not self._touchIsDown and self._endX+self._container:getContentSize().width>self:getContentSize().width then 
            speedX = speedX * 0.2
        elseif not self._touchIsDown and self._endX>0 then 
            speedX = speedX * 0.2
        end
        if  speedX>self.maxSpeed then 
            speedX= self.maxSpeed 
        elseif speedX <-self.maxSpeed then 
            speedX= -self.maxSpeed 
        end
        if math.abs(speedX)<0.1 then 
            speedX = 0 
            self._container:setPositionX( self._endX )
        else
            self._container:setPositionX( self._container:getPositionX()+speedX )
        end
        spd = speedX
    end

    --是否需要render
    if spd~=0 then
        for _, child in ipairs(self._container:getChildren()) do
            if  child:getPositionX()+self._container:getPositionX()+self._renderSize.width<0 or
                child:getPositionX()+self._container:getPositionX()-self._renderSize.width>self:getContentSize().width or
                child:getPositionY()+self._container:getPositionY()>self._renderSize.height or
                child:getPositionY()+self._container:getPositionY()+self._renderSize.height<-self:getContentSize().height
            then
                if child:isVisible() then
                    child:setVisible(false)
                    if child._onBecameInVisibleFun~=nil then
                        child._onBecameInVisibleFun(child)
                    end
                end
            else
                if not child:isVisible() then
                    child:setVisible(true)
                    if child._onBecameVisibleFun~=nil then
                        child._onBecameVisibleFun(child)
                    end
                end 
            end
        end
    end
end




function UIScrollView:_onTouchHandler(event)
    if self.lockDrag then return end
    local name,x,y,prevX,prevY = event.name,event.x,event.y,event.prevX,event.prevY
    if name=="began" then

        self._touchIsDown = true
        self._beganPos.x = x
        self._beganPos.y = y
        self._containerPos.x = self._container:getPositionX()
        self._containerPos.y = self._container:getPositionY()
        self._endX = self._containerPos.x
        self._endY = self._containerPos.y
        self._delta.x = 0
        self._delta.y = 0
        self._offsetX= 0
        self._offsetY =0
        return true
    elseif name=="moved" then

        self.touchChildren = false
        self._offsetX = x-self._beganPos.x
        self._offsetY = y-self._beganPos.y

        self._endX = self._containerPos.x + self._offsetX 
        self._endY = self._containerPos.y + self._offsetY

        self._delta.x = x-prevX
        self._delta.y = y-prevY

    elseif name=="ended" or name=="cancelled" then

        self._touchIsDown =false 
        self.touchChildren = true

        self._offsetX = x-self._beganPos.x
        self._offsetY = y-self._beganPos.y

        if self.direction==UIScrollView.DIRECTION_HORIZONTAL then

            if math.abs(self._offsetX)>10 then
                self._endX =  self._endX + self._offsetX
            else self._endX = self._container:getPositionX() end

            if self._endX>0 or self._container:getContentSize().width<self:getContentSize().width then 
                self._endX=0 
            elseif self._endX<-self._container:getContentSize().width+self:getContentSize().width+self._renderSize.width then
                self._endX = -self._container:getContentSize().width+self:getContentSize().width+self._renderSize.width 
            end

        elseif self.direction==UIScrollView.DIRECTION_VERTICAL then

            if math.abs(self._offsetY)>10 then
                self._endY =  self._endY + self._offsetY
            else self._endY = self._container:getPositionY() end


            if self._endY<0 or self._container:getContentSize().height<self:getContentSize().height then
                self._endY=0 
            elseif self._endY>self._container:getContentSize().height-self:getContentSize().height-self._renderSize.height then
                self._endY = self._container:getContentSize().height-self:getContentSize().height-self._renderSize.height
            end 
        end
    end

end

function UIScrollView:getRenders()
    return self._container:getChildren()
end

function UIScrollView:dispose()
    self._container = nil 
    self._clipNode = nil
    UIScrollView.super.dispose(self)
end

return UIScrollView